package com.buddy.learn.spring.framework.beans.support;

import com.buddy.learn.spring.framework.beans.config.BBeanDefinition;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class BBeanDefinitionReader {

    private List<String> registyBeanClasses = new ArrayList<>();


    private Properties config = new Properties();

    //固定配置文件中的key，相当于xml的规范
    private final String SCANNER_PACKAGE = "scanPackage";

    public BBeanDefinitionReader(String... locations) {

        //通过URL定位找到其所对应的文件，然后转换为文件流
//        InputStream is = this.getClass().getClassLoader().getResourceAsStream(locations[0].replace("classpath", ""));
        InputStream is = this.getClass().getResourceAsStream(locations[0].replace("classpath", ""));

        try {
            config.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        doScanner(config.getProperty(SCANNER_PACKAGE));
    }

    private void doScanner(String scanPackage) {
        //转换为文件路径，将.替换为/
        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replace("\\.", "/"));
        File classPath = new File(url.getFile());
        for (File file : classPath.listFiles()) {
            if (file.isDirectory()) {
                doScanner(scanPackage + "." + file.getName());
            } else {
                if (!file.getName().endsWith(".class")) {
                    continue;
                }
                String className = scanPackage + "." + file.getName().replace(".class", "");
                registyBeanClasses.add(className);
            }
        }
    }

    public Properties getConfig() {
        return this.config;
    }

    /**
     * 把配置文件中扫描到的所有配置信息转换为BeanDefinition对象，以便之后IOC操作方便
     * @return
     */
    public List<BBeanDefinition> loadBeanDefinitions() {

        List<BBeanDefinition> result = new ArrayList<>();
        try {
            for (String className : registyBeanClasses) {

                Class<?> beanClass = Class.forName(className);

                //如果是一个接口，是不能实例化的
                //用他的实现类来实例化
                if (beanClass.isInterface()) continue;
                BBeanDefinition beanDefinition = doCreateBeanDefinition(className);
                if (null == beanDefinition) continue;
                result.add(beanDefinition);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        return result;

    }

    /**
     * 把配置信息解析为一个BeanDefinition
     *
     * @param className
     * @return
     */
    private BBeanDefinition doCreateBeanDefinition(String className) {
        try {
            Class<?> beanClass = Class.forName(className);
            //有可能是一个接口，用他的实现类作为beanClassName
            if (beanClass.isInterface()) return null;
            BBeanDefinition beanDefinition = new BBeanDefinition();
            beanDefinition.setBeanClassName(className);
            beanDefinition.setFactoryBeanName(beanClass.getSimpleName());
            return beanDefinition;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
